Skip to content

v1.2.0#18

Open
hoangsvit wants to merge 69 commits into
mainfrom
dev
Open

v1.2.0#18
hoangsvit wants to merge 69 commits into
mainfrom
dev

Conversation

@hoangsvit

@hoangsvit hoangsvit commented Jul 1, 2026

Copy link
Copy Markdown
Member

Description

What's new?

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Tests
  • Other

Screenshots

- Implemented QR code generation for email aliases using the `qrcode` library.
- Added a modal to display the QR code and options to copy it.
- Introduced bulk delete functionality for selected aliases.
- Enhanced settings to include theme selection with light, dark, and auto modes.
- Updated UI components to support dark mode styling.
- Added toast notifications for user feedback on actions like adding presets, switching accounts, and exporting settings.
- Improved export functionality for aliases in CSV and JSON formats.
- Refactored settings component to manage theme changes and display toast messages.
- Updated Input component to support dark mode styles for labels and input fields.
- Modified Settings component to include dark mode styles for backgrounds, text colors, and borders throughout various sections.
- Improved Statistics component with dark mode compatibility for background colors and text.
- Enhanced Toggle component to reflect dark mode styles for labels and descriptions.
- Simplified the layout and styling of the WelcomeScreen component for better responsiveness and visual appeal.
- Replaced the logo with an image and adjusted text sizes for improved readability.
- Updated input field styles and validation error messages for consistency.
- Added a new SVG icon for email representation and removed outdated PNG icons.
- Cleaned up unused icon files to streamline the project assets.
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release 1.2.0: QR codes, bulk delete, dark mode, tests & CI updates

✨ Enhancement 🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add QR-code modal and bulk delete for managing generated aliases.
• Introduce theme selection and dark mode styling across popup and settings.
• Add Vitest test suite and update CI/release workflows for Yarn/Corepack.
Diagram

graph TD
  App["Popup App"] --> Settings["Settings modal"] --> Storage[("Extension storage")]
  App --> Utils["Shared utils"] --> Storage
  App --> QR["QR modal"] --> QRLib{{"qrcode lib"}}
  ThemeCfg["Tailwind dark mode"] --> App
  Tests["Vitest tests"] --> Utils
  CI["GitHub Actions"] --> Build["WXT build"]
  subgraph Legend
    direction LR
    _ui["UI component"] ~~~ _util["Utility module"] ~~~ _db[("Storage")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize theme handling via a Theme hook/context
  • ➕ Avoids duplicated matchMedia + documentElement.classList.toggle logic in App/Settings
  • ➕ Makes future theming (e.g., per-account theme) easier to implement/test
  • ➖ Adds a small amount of structural overhead (provider + hook)
  • ➖ Not necessary if theme logic remains minimal
2. Introduce a storage repository wrapper (typed)
  • ➕ Reduces repeated key construction + casting of storage results (as any[])
  • ➕ Enables easier mocking and stronger testability for storage-heavy logic
  • ➖ More upfront refactor work
  • ➖ May slow iteration if the project remains small
3. Use a dedicated QR React component/library wrapper
  • ➕ Encapsulates canvas lifecycle and sizing; easier to reuse/test
  • ➕ Potentially reduces direct DOM ref handling in App
  • ➖ Extra abstraction; current usage is straightforward
  • ➖ May add bundle size if over-engineered

Recommendation: Current approach is reasonable for v1.2.0: extracting pure helpers into utils.ts and adding tests is a strong direction, and the QR integration is appropriately lightweight. The main strategic improvement to consider is consolidating theme toggling and storage access behind small shared abstractions to reduce duplication and casting as the feature set continues to grow.

Files changed (24) +1707 / -742

Enhancement (5) +804 / -500
App.tsxAdd QR modal, bulk delete, exports, batched history/stats, and theme support +486/-276

Add QR modal, bulk delete, exports, batched history/stats, and theme support

• Implements QR-code rendering for an alias, bulk selection + delete, and alias export (CSV/JSON), while adding toast feedback and fixing Copy All stats via batched saves. Refactors core logic to shared utilities, improves modal positioning (scroll to top on open), and applies class-based dark mode driven by persisted theme.

entrypoints/popup/App.tsx

Button.tsxUpdate Button styling for new rounded/gradient + dark mode variants +5/-5

Update Button styling for new rounded/gradient + dark mode variants

• Adjusts base/variant Tailwind classes to match the updated UI style, including dark-mode variants for non-primary buttons.

entrypoints/popup/components/Button.tsx

Input.tsxAdd dark mode styles and rounded-full input design +2/-2

Add dark mode styles and rounded-full input design

• Updates label and input classes to support dark mode and the new rounded-full control style.

entrypoints/popup/components/Input.tsx

Settings.tsxRedesign settings UI, add theme selector, toasts, and in-app changelog tab +308/-214

Redesign settings UI, add theme selector, toasts, and in-app changelog tab

• Adds a new changelog tab, integrates toast notifications for settings actions, and introduces functional theme selection (light/dark/auto) with class toggling. Also refactors account handling details (case-insensitive uniqueness, first-account activation behavior) and applies extensive dark-mode styling updates.

entrypoints/popup/components/Settings.tsx

Toggle.tsxAdd dark mode styles to Toggle component +3/-3

Add dark mode styles to Toggle component

• Updates label/description and disabled-state background classes to render correctly under dark mode.

entrypoints/popup/components/Toggle.tsx

Bug fix (2) +94 / -111
WelcomeScreen.tsxCentralize email validation and fix Tab key behavior for domain completion +90/-108

Centralize email validation and fix Tab key behavior for domain completion

• Moves email validation to shared utils, changes domain auto-completion from intercepting Tab to completing on blur, and updates the onboarding UI to the new layout.

entrypoints/popup/components/WelcomeScreen.tsx

style.cssFix popup sizing and scrolling behavior +4/-3

Fix popup sizing and scrolling behavior

• Updates popup dimensions and constrains overflow so content scrolls within the popup, not the whole page.

entrypoints/popup/style.css

Refactor (3) +224 / -119
GmailTricks.tsxMove dot-variation generation to utils and align styling with dark mode +35/-88

Move dot-variation generation to utils and align styling with dark mode

• Replaces inline dot-variation generation with 'generateDotVariations' from shared utils and updates styling to the new blue/dark theme palette.

entrypoints/popup/components/GmailTricks.tsx

Statistics.tsxUse shared storage key helper and refresh UI styling for dark mode +44/-31

Use shared storage key helper and refresh UI styling for dark mode

• Replaces duplicated storage-key logic with 'getAccountStorageKey' and updates the statistics panel layout/styling for the new card design and dark mode.

entrypoints/popup/components/Statistics.tsx

utils.tsIntroduce shared pure utilities for generation, validation, and filtering +145/-0

Introduce shared pure utilities for generation, validation, and filtering

• Adds shared helpers for account-scoped storage keys, alias/tag generation, random formats, email validation with warnings, dot-variation generation, and alias filtering/sorting.

entrypoints/popup/utils.ts

Tests (5) +478 / -0
Button.test.tsxAdd Button component unit tests +57/-0

Add Button component unit tests

• Introduces Testing Library tests covering rendering, click behavior, disabled behavior, variants, and sizing.

entrypoints/popup/components/tests/Button.test.tsx

Input.test.tsxAdd Input component unit tests +54/-0

Add Input component unit tests

• Adds tests validating label rendering, placeholder/value behavior, change events, disabled state, and keypress callback wiring.

entrypoints/popup/components/tests/Input.test.tsx

Toggle.test.tsxAdd Toggle component unit tests +56/-0

Add Toggle component unit tests

• Adds tests for label/description rendering, switch toggling semantics, aria-checked attributes, and enabled/disabled styling classes.

entrypoints/popup/components/tests/Toggle.test.tsx

utils.test.tsAdd comprehensive unit tests for popup utilities +286/-0

Add comprehensive unit tests for popup utilities

• Adds Vitest coverage for storage key generation, alias and random string generation, email validation, dot variation generation, and alias list filtering/sorting.

entrypoints/popup/utils.test.ts

setup.tsAdd Vitest test setup with extension/browser mocks +25/-0

Add Vitest test setup with extension/browser mocks

• Configures jest-dom matchers and mocks 'browser.storage.local' and 'navigator.clipboard' for component/unit tests.

test/setup.ts

Documentation (1) +17 / -0
CHANGELOG.mdAdd 1.2.0 changelog entry +17/-0

Add 1.2.0 changelog entry

• Adds Keep-a-Changelog formatted release notes for 1.2.0, capturing UI changes and key bug fixes (Copy All stats, modal bounds, Tab behavior).

CHANGELOG.md

Other (8) +90 / -12
ci.ymlAdd CI workflow for Node 24 + Yarn/Corepack + WXT build +37/-0

Add CI workflow for Node 24 + Yarn/Corepack + WXT build

• Introduces a new CI workflow triggered on pushes/PRs to main. Uses Node 24 with Corepack and installs via Yarn immutable mode, then runs WXT prepare and builds the extension.

.github/workflows/ci.yml

dependabot-auto-merge.ymlBump dependabot metadata action version +1/-1

Bump dependabot metadata action version

• Updates 'dependabot/fetch-metadata' from v2.4.0 to v3.1.0 for the auto-merge workflow.

.github/workflows/dependabot-auto-merge.yml

pr-closed.ymlUpdate PR-closed workflow naming and github-script action pin +2/-2

Update PR-closed workflow naming and github-script action pin

• Renames the workflow to a plain title and updates the pinned 'actions/github-script' revision to v9.0.0.

.github/workflows/pr-closed.yml

release.ymlModernize release workflow (Node 24, Corepack, WXT prepare, actions bumps) +11/-7

Modernize release workflow (Node 24, Corepack, WXT prepare, actions bumps)

• Updates checkout action, Node version, and Yarn install flags, and adds a WXT prepare step. Also bumps the GitHub Release action and adjusts submission command invocation.

.github/workflows/release.yml

package.jsonBump version to 1.2.0 and add QR/test/tooling dependencies +18/-2

Bump version to 1.2.0 and add QR/test/tooling dependencies

• Updates project version, pins Yarn via packageManager, requires Node >=24, adds qrcode, and introduces Vitest + Testing Library dependencies and scripts.

package.json

tailwind.config.tsEnable class-based dark mode +1/-0

Enable class-based dark mode

• Turns on 'darkMode: 'class'' to support explicit theme toggling via a root class.

tailwind.config.ts

vitest.config.tsAdd Vitest configuration for React + jsdom +14/-0

Add Vitest configuration for React + jsdom

• Adds Vitest config enabling jsdom, globals, setup files, include/exclude patterns, and React plugin integration.

vitest.config.ts

wxt.config.tsAdd Vite defines for process shims +6/-0

Add Vite defines for process shims

• Adds Vite 'define' shims for 'process.emit' and 'process.env' to avoid runtime/bundling issues in the extension build.

wxt.config.ts

@qodo-code-review

qodo-code-review Bot commented Jul 1, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Storage key collisions ✓ Resolved 🐞 Bug ≡ Correctness
Description
getAccountStorageKey() normalizes emails by replacing all non-alphanumerics with '_', which can map
different emails to the same storage key and silently mix/overwrite per-account
history/favorites/stats. This breaks account isolation when two distinct emails sanitize to the same
string.
Code

entrypoints/popup/utils.ts[R1-4]

+export function getAccountStorageKey(email: string, suffix: string): string {
+  const sanitized = email.replace(/[^a-zA-Z0-9]/g, '_');
+  return `${suffix}_${sanitized}`;
+}
Evidence
The key generator collapses many distinct emails into the same sanitized string, and the result is
used to namespace account-specific data in multiple places (history/stats/favorites).

entrypoints/popup/utils.ts[1-4]
entrypoints/popup/App.tsx[103-137]
entrypoints/popup/components/WelcomeScreen.tsx[47-62]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getAccountStorageKey()` is not injective: replacing all non-alphanumeric characters with `_` can cause different emails to generate the same storage key, leading to data overwrites between accounts.

### Issue Context
Account-specific storage keys are used for history, favorites, and stats; collisions break separation.

### Fix Focus Areas
- entrypoints/popup/utils.ts[1-4]
- entrypoints/popup/App.tsx[103-137]
- entrypoints/popup/components/WelcomeScreen.tsx[47-62]

### Suggested fix
- Replace the sanitizer with a collision-resistant encoding, e.g.:
 - `const encoded = encodeURIComponent(email.toLowerCase())` and use it directly (safe chars), or
 - `base64url(email)` (and strip padding), or
 - `sha256(email)` (shorten) if you want bounded key length.
- Keep the suffix prefixing (`${suffix}_...`) but ensure the email portion cannot collide for distinct inputs.
- If you already have persisted data, consider a migration strategy to read legacy keys and write new keys once.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Notification toggle ignored ✓ Resolved 🐞 Bug ≡ Correctness
Description
Settings persists a "Copy notifications" toggle, but App.copyToClipboard() always shows a toast, so
the toggle has no effect. App also never reads showNotifications from app_settings when loading
settings, so the preference is effectively unused.
Code

entrypoints/popup/App.tsx[R455-467]

  const copyToClipboard = async (email: string) => {
    try {
      await navigator.clipboard.writeText(email);
      setCopiedEmail(email);
+      setToastMessage('✓ Copied to clipboard!');
      saveRecentAlias(email);
-      setTimeout(() => setCopiedEmail(null), 2000);
+      setTimeout(() => {
+        setCopiedEmail(null);
+        setToastMessage(null);
+      }, 2000);
    } catch (err) {
-      console.error('Failed to copy:', err);
+      setToastMessage('✗ Failed to copy');
+      setTimeout(() => setToastMessage(null), 2000);
Evidence
Settings writes the preference, but App never reads it and unconditionally sets toastMessage on
copy.

entrypoints/popup/components/Settings.tsx[525-531]
entrypoints/popup/App.tsx[140-147]
entrypoints/popup/App.tsx[455-467]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The UI lets users disable copy notifications, but the popup always emits toast messages on copy. The preference is saved but not applied.

### Issue Context
- Settings toggles `settings.showNotifications`.
- App loads some `app_settings` fields but does not load or apply `showNotifications`.

### Fix Focus Areas
- entrypoints/popup/App.tsx[140-147]
- entrypoints/popup/App.tsx[455-467]
- entrypoints/popup/components/Settings.tsx[525-531]

### Suggested fix
- Add `const [showNotifications, setShowNotifications] = useState(true)` in App.
- When loading `app_settings` (and on storage changes), set `showNotifications` from `app_settings.showNotifications` (default true).
- Gate all toast setters (copy/export/delete/etc.) behind `if (showNotifications) { ... }`.
- Optionally also gate `copiedEmail` UI if it's part of the same notification concept.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Gmail substring validation ✓ Resolved 🐞 Bug ≡ Correctness
Description
validateEmail() treats any domain containing the substring "gmail" as Gmail, so inputs like
user@gmail.evil.com will be accepted without the Gmail warning. This misclassifies addresses in
WelcomeScreen where validateEmail gates account creation and guidance.
Code

entrypoints/popup/utils.ts[R52-65]

+export function validateEmail(value: string): ValidationResult {
+  if (!value.trim()) return { isValid: false, error: 'Email is required' };
+  if (!value.includes('@')) return { isValid: false, error: 'Please enter a valid email address' };
+
+  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+  if (!emailRegex.test(value)) return { isValid: false, error: 'Invalid email format' };
+
+  const [username, domain] = value.split('@');
+  if (username.length < 1) return { isValid: false, error: 'Username cannot be empty' };
+  if (!domain.includes('.')) return { isValid: false, error: 'Domain must include a dot (e.g., gmail.com)' };
+
+  if (!domain.includes('gmail') && !domain.includes('googlemail')) {
+    return { isValid: true, warning: '⚠️ Works best with Gmail addresses' };
+  }
Evidence
The validator uses domain.includes('gmail')/domain.includes('googlemail'), and WelcomeScreen
relies on this validator to decide validity and warnings.

entrypoints/popup/utils.ts[52-67]
entrypoints/popup/components/WelcomeScreen.tsx[14-24]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Domain classification uses substring checks (`includes('gmail')`), which can misclassify non-Gmail domains that merely contain the substring.

### Issue Context
`WelcomeScreen` uses `validateEmail()` for both blocking invalid input and for showing guidance.

### Fix Focus Areas
- entrypoints/popup/utils.ts[52-67]
- entrypoints/popup/components/WelcomeScreen.tsx[14-24]

### Suggested fix
- Normalize `domain` to lowercase and use an exact allowlist:
 - `const d = domain.toLowerCase(); const isGmail = d === 'gmail.com' || d === 'googlemail.com';`
- Only suppress the warning when `isGmail` is true.
- (Optional follow-up) Reuse the same predicate for Gmail-only features elsewhere (e.g., dot-trick generation) to keep behavior consistent.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Unhandled QRCode rejection ✓ Resolved 🐞 Bug ☼ Reliability
Description
QRCode.toCanvas() is invoked without awaiting or catching failures, so QR generation errors can
surface as unhandled promise rejections and leave the QR UI in an inconsistent state. This reduces
reliability of the QR modal flow.
Code

entrypoints/popup/App.tsx[R306-310]

+  useEffect(() => {
+    if (qrAlias && qrCanvasRef.current) {
+      QRCode.toCanvas(qrCanvasRef.current, qrAlias, { width: 200, margin: 2 });
+    }
+  }, [qrAlias]);
Evidence
The code triggers QRCode.toCanvas but does not handle the returned Promise at all.

entrypoints/popup/App.tsx[305-310]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`QRCode.toCanvas(...)` returns a Promise; calling it in an effect without `await`/`.catch()` can lead to unhandled rejections when QR rendering fails.

### Issue Context
This runs every time `qrAlias` changes.

### Fix Focus Areas
- entrypoints/popup/App.tsx[305-310]

### Suggested fix
- Wrap the call in a handled Promise, e.g.:
 - `void QRCode.toCanvas(...).catch((e) => { /* set error toast or state */ })`
 - or use an async IIFE in the effect with try/catch.
- Optionally clear the canvas when `qrAlias` becomes null, and/or show an inline error message in the modal if generation fails.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread entrypoints/popup/utils.ts
Comment thread entrypoints/popup/App.tsx Outdated
Comment thread entrypoints/popup/App.tsx Outdated
Comment thread entrypoints/popup/utils.ts
@deepsource-io

deepsource-io Bot commented Jul 2, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in b35c1d5...4e86bdf on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Jul 2, 2026 10:37a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

hoangsvit and others added 6 commits July 2, 2026 08:36
This commit fixes the style issues introduced in 02be370 according to the output
from Prettier.

Details: #18
This commit fixes the style issues introduced in 7398ec8 according to the output
from Prettier.

Details: #18

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by eplus-bot bot@eplus.dev after CI passed.

eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…Tricks component

test: implement unit tests for GmailTricks component and email utility functions
This commit fixes the style issues introduced in 2e6c0c1 according to the output
from Prettier.

Details: #18

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit fixes the style issues introduced in e3967d6 according to the output
from Prettier.

Details: #18
eplus-bot
eplus-bot previously approved these changes Jul 2, 2026

@eplus-bot eplus-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eplus-bot

Copy link
Copy Markdown
Contributor

CI passed

Approved by @eplus-bot after CI passed.

Updated: 2026-07-02T10:37:13Z
Run attempt: #1

CI run: https://github.com/ePlus-DEV/gmail-alias-toolkit/actions/runs/28583713651

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants